#pragma once

template <size_t N>
constexpr size_t AddN = std::ratio_add<std::ratio<N>, std::ratio<1>>::num;
template <size_t N>
constexpr size_t DecN = std::ratio_subtract<std::ratio<N>, std::ratio<1>>::num;

template<size_t X, size_t N>
constexpr size_t PowN = std::ratio_multiply<std::ratio<X>, std::ratio<PowN<X, DecN<N>>>>::num;

template<size_t X>
constexpr size_t PowN<X, 0> = 1;

template<size_t N> constexpr size_t Bin = 1;
template<> constexpr size_t Bin<0> = 0;

template<size_t...>constexpr size_t Bit = 0;
template<size_t First, size_t... Rest>
constexpr size_t Bit<First, Rest...> = std::ratio_add<std::ratio<std::ratio_multiply<std::ratio<Bin<First>>, std::ratio<PowN<2, sizeof...(Rest)>>>::num>, std::ratio<Bit<Rest...>>>::num;
template<size_t N>
constexpr size_t Bit<N> = Bin<N>;

template<size_t N>
constexpr size_t BitN = std::ratio_add<std::ratio<BitN<DecN<N>>>, std::ratio<PowN<2, DecN<N>>>>::num;
template<> constexpr size_t BitN<0> = 0;

namespace hAdvanceDetail 
{
	template<typename InputIt>
	void callback(InputIt& it, size_t n)
	{
		while (n > 0) 
		{
			--n;
			++it;
		}
	}

} // namespace detail

template<typename InputIt>
void hAdvance(InputIt& it, size_t n = 1)
{
	hAdvanceDetail::callback(it, n);
}

template<class InputIt>
InputIt hNext(InputIt it, size_t n = 1)
{
	hAdvance(it, n);
	return it;
}